﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using ServiceDeskClient.ServiceDeskServiceReference;
using System.Windows.Threading;
namespace ServiceDeskClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        public MainWindow(IServiceDeskService service, LoginDTO userLogin )
        {
            InitializeComponent();
            this.DataContext = _Model = new Model(Dispatcher, service, userLogin);
            Loaded += (s, e) => _Model.Fill();
                
        }
        private readonly Model _Model;

        internal class Model
        {
            public Model( Dispatcher dispatcher , IServiceDeskService service, LoginDTO userLogin)
            {
                IsAdminMode = userLogin.Role == RoleDTO.Admin;
                Service = service;
                Dispatcher = dispatcher;
                Users = new ObservableCollection<UserItem>();
                Tasks = new ObservableCollection<TaskItem>();
                NewUser = new NewUserModel();
                UserLogin = userLogin;
           
                if (IsAdminMode)
                {
                    UsersTabVisibility = Visibility.Collapsed;
                }
                else
                {
                    UsersManagmentTabVisibility = Visibility.Collapsed;
                }
            }
            private readonly bool IsAdminMode ;
            private readonly LoginDTO UserLogin;
            public Visibility UsersTabVisibility { get; private set; }
            public Visibility UsersManagmentTabVisibility { get; private set; }
            private readonly IServiceDeskService Service;
            private readonly Dispatcher Dispatcher;
            internal class SimpleCommand : ICommand
            {

                public SimpleCommand(Action a)
                {
                    Action = a;
                }
                private Action Action;
                public bool CanExecute(object parameter)
                {
                    return true;
                }

                public event EventHandler CanExecuteChanged
                {
                    add { }
                    remove { }
                }

                public void Execute(object parameter)
                {
                    Action();
                }
            }
            private Action AssignAction(Guid taskGuid)
            {
                return () =>
                    {
                        var selectForm = new SelectUserWindow(Users.Where(u=>u.Role==RoleDTO.Operator).ToList());
                        if (
                            (selectForm.ShowDialog() == true)&&
                            (selectForm.Result!=null))
                        {
                            Assing(taskGuid, selectForm.Result.Value);
                        }
                    };
            }
            private void Assing(Guid taskGuid, Guid userGuid)
            {

                var task = new Task(() =>
                {
                    Service.Assign(taskGuid, userGuid);
                });
                ContinueWithFill(task);
                ProgressBar.RunWithProgressBar(task);

            }

            public class UserItem
            {
                public UserItem(UserDTO user, Action remove)
                {
                    Role = user.Role;
                    RoleName = GetRoleName(Role);
                    Login = user.Login;
                    RemoveCommand = new SimpleCommand(remove);
                    Guid = user.Guid;
                }

                public string Login{get;private set;}
                public readonly RoleDTO Role;
                public string RoleName { get; private set; }
                public ICommand RemoveCommand { get; private set; }
                public readonly Guid Guid;
                private static string GetRoleName(RoleDTO role)// TODO: это нужно локализовать
                {
                    switch (role)
                    {
                        case RoleDTO.Admin:
                            return "Администратор";
                        case RoleDTO.Operator:
                            return "Оператор"; 
                        default :
                            return "Неизвестно";
                    }

                }
            
            }

            public ObservableCollection<UserItem> Users{get;private set;}
            public class TaskItem
            {
                public TaskItem(TaskDTO task, string assigneeName , bool canAssign,  Action assign, bool canSetStaus, Action setStatusAction)
                {
                    Description = task.Description;
                    StatusName = GetStatusName(task.TaskStatus);
                    AssigneeName = assigneeName;
                    AssignCommand = new SimpleCommand(assign);
                    AssignButtonVisibility = canAssign? Visibility.Visible:Visibility.Hidden;
                    SetStatusButtonVisibility = canSetStaus ? Visibility.Visible : Visibility.Hidden;
                    SetStatusCommand = new SimpleCommand(setStatusAction);
                }
                public ICommand AssignCommand { get; private set; }
                public string Description{get;private set;}
                public string StatusName{get;private set;}
                public string AssigneeName { get; private set; }
                public Visibility AssignButtonVisibility { get; private set; }
                public ICommand SetStatusCommand { get;private set; }
                public Visibility SetStatusButtonVisibility { get; private  set; }
                internal static string GetStatusName( TaskStateDTO status)// TODO: это нужно локализовать
                {
                    switch (status)
                    {
                        case TaskStateDTO.Open :
                            return "Открыта";
                        case TaskStateDTO.InProgress:
                            return "В работе";
                        case TaskStateDTO.Closed:
                            return "Закрыта";
                        default:
                            return "Неизвестно";
                    }

                }

            }

            public ObservableCollection<TaskItem> Tasks { get; private set; }

            private Action RemoveAction(Guid g)
            {
                return new Action(
                    ()=>
                        {
                            if(UserLogin.Role== RoleDTO.Admin)
                            { 
                                RemoveUser(g);
                            }
                        });
            }

            private Action SetStatusAction(Guid taskGuid)
            {
                return () =>
                    {
                        var selectStatusForm = new SelectStatusWindow();
                        if (
                            selectStatusForm.ShowDialog() == true &&
                            selectStatusForm.Result != null)
                        {
                            var task = new Task(() =>
                                            Service.SetTaskState(taskGuid, selectStatusForm.Result.Value));
                            ContinueWithFill(task);
                            ProgressBar.RunWithProgressBar(task);
                        }
                    };
            }


            private Task ContinueWithFill(Task task)
            {
                return
                    task.ContinueWith<IEnumerable<UserDTO>>(
                            o =>
                                Service.ListUsers())
                        .ContinueWith(
                            userList =>
                            {
                                var tasks = Service.ListTasks();
                                if (!userList.IsFaulted)
                                {
                                    return Tuple.Create(userList.Result, tasks.AsEnumerable());
                                }
                                else
                                {
                                    return null as Tuple<IEnumerable<UserDTO>, IEnumerable<TaskDTO>>;
                                }
                            })
                        .ContinueWith(usersAndTasks =>
                        {
                            Dispatcher.SimpleInvoke(
                                () =>
                                {
                                    Users.Clear();
                                    Tasks.Clear();
                                    if (usersAndTasks.IsFaulted)
                                    {
                                        MessageBox.Show("Ошибка получения данных");// TODO нужно локализовать, и разбирать причину
                                    }
                                    else
                                    {
                                        var users = usersAndTasks.Result.Item1.OrderBy(u=>u.Login);
                                        var tasks = usersAndTasks.Result.Item2.OrderBy(t => t.TaskGuid);
                                        var userItems = users.Select(
                                                                        u => new UserItem(
                                                                            u,
                                                                            RemoveAction(u.Guid)))
                                                                .ToList();
                                                                            

                                        foreach (var u in userItems)
                                        {
                                            Users.Add(u);
                                        }
                                        var taskItems = tasks.Select(t =>
                                                                    new TaskItem(
                                                                            t,

                                                                            users
                                                                                .Where(u => u.Guid == t.UserGuid)
                                                                                .Select(u => u.Login)
                                                                                .FirstOrDefault(),
                                                                            UserLogin.Role == RoleDTO.Admin,
                                                                            AssignAction(t.TaskGuid),
                                                                            UserLogin.Role == RoleDTO.Admin || t.UserGuid == UserLogin.Guid,
                                                                            SetStatusAction(t.TaskGuid)                                                                            
                                                                            ))
                                                                .ToList();
                                        foreach (var t in taskItems)
                                        {
                                            Tasks.Add(t);
                                        }




                                    }
                                });
                        });
            }

            public void Fill()
            {
                var task = new Task<object>(() => new object());
                ContinueWithFill(task);

                ProgressBar.RunWithProgressBar( task);
                    

            }
            public void AddUser()
            {
                // TODO здесь можно делать валадацию пользовтельского ввода
                var task = new Task<UserDTO>(() =>
                                {
                                    return
                                     Service.AddUser(NewUser.Login, NewUser.Password, NewUser.IsAdmin ? RoleDTO.Admin : RoleDTO.Operator);
                                });
                task.ContinueWith(user =>
                    {
                        Dispatcher.SimpleInvoke(() =>
                                            {
                                                if (user.IsFaulted)
                                                {
                                                    MessageBox.Show("Ошибка");// TODO здесь можно анализировать тип ошибки, и выдвать более умное сообщение
                                                }
                                                else
                                                {
                                                    Users.Add(new UserItem( user.Result, RemoveAction(user.Result.Guid) ));
                                                }
                                            });
                    });
                ProgressBar.RunWithProgressBar(task);

            }
            public void RemoveUser(Guid guid)
            {
                var task = new Task<bool>(() =>
                                Service.RemoveUser(guid));

                ContinueWithFill(task);
                ProgressBar.RunWithProgressBar(task);

            }

            public class NewUserModel
            {
                public string Login { get; set; }
                public string Password { get; set; }
                public bool IsAdmin { get; set; }
            }
            public NewUserModel NewUser { get; private set; }
        }

        private void AddUser_Click(object sender, RoutedEventArgs e)
        {
            _Model.AddUser();
        }

    }
}
